package insight;

import lombok.Data;

import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;

@Data
public class MyThreadPool {

    BlockingQueue<Runnable> blockingQueue = new ArrayBlockingQueue<>(1024);
    private int corePoolSize = 2;
    private int maximumPoolSize = 10;
    private long keepAliveTime = 1000;
    private TimeUnit timeUnit = TimeUnit.MILLISECONDS;
    private List<Thread> coreThreadsList = new ArrayList<>();
    private List<Thread> extraThreadsList = new ArrayList<>();
    private RejectHandle rejectHandle = new ExceptionRejuctHandle();
    //command指的是线程池需要执行的任务
    private final Object coreLock = new Object();
    private final Object extraLock = new Object();
    void execute(Runnable command){
        synchronized (coreLock){
            if(coreThreadsList.size() < corePoolSize){
                Thread thread = new CoreThread(command);
                coreThreadsList.add(thread);
                thread.start();
                return;
            }
        }
        if(blockingQueue.offer(command)){
            return;
        }
        synchronized (extraLock){
            if(extraThreadsList.size() < maximumPoolSize - corePoolSize){
                Thread thread = new ExtraThread(command);
                extraThreadsList.add(thread);
                thread.start();
                return;
            }
        }
        if(!blockingQueue.offer(command)){
            rejectHandle.reject(command, this);
        }
    }

    public MyThreadPool( int corePoolSize, int maximumPoolSize, long keepAliveTime, TimeUnit timeUnit, BlockingQueue<Runnable> blockingQueue, RejectHandle rejectHandle) {
        this.blockingQueue = blockingQueue;
        this.corePoolSize = corePoolSize;
        this.maximumPoolSize = maximumPoolSize;
        this.keepAliveTime = keepAliveTime;
        this.timeUnit = timeUnit;
        this.rejectHandle = rejectHandle;
    }

    public MyThreadPool() {
    }

    class CoreThread extends Thread{

        private final Runnable firstTask;

        public CoreThread(Runnable firstTask) {
            this.firstTask = firstTask;
        }
        @Override
        public void run() {
            firstTask.run();
            while(true){
                try {
                    Runnable command = blockingQueue.take();
                    command.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        }
    }

    class ExtraThread extends Thread {

        private final Runnable firstTask;

        public ExtraThread(Runnable firstTask) {
            this.firstTask = firstTask;
        }
        @Override
        public void run() {
            firstTask.run();
            while (true) {
                try {
                    Runnable command = blockingQueue.poll(keepAliveTime, timeUnit);
                    if (command == null) {
                        break;
                    }
                    command.run();
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
            System.out.println(Thread.currentThread().getName() + "线程结束了");
            extraThreadsList.remove(Thread.currentThread());
        }
    }
}